!function () {
    var gw = {
        version: "0.0.1",
        clsTreeBody: ".gw-tree-body",
        htmlWait: "<div class='gw-wait' style='height:100%;width:100%;background:white;display:table;border-radius:6px;'>"
                + "<span style='display:table-cell;text-align:center;vertical-align:middle;'>"
                + "<i class='fa fa-cog fa-5x fa-spin'></i></span></div>",
        clsTreeSearchHeader: ".gw-search",
        clsSearchMain: ".gw-search-main",
        clsSearchMainButton: ".gw-search-button-main",
        clsSearchText: ".gw-search-text",
        clsSearchHilghlight: "gw-search-hl",
        clsSearchHilghlightTarget: ".gw-search-hl-trgt",
        clsShowHide: ".gw-showhide",
        clsPressedBack: "gw-pressed-bck",
        clsShowHideChild: ".gw-showhide-chld",
        clsCellSearch: ".gw-cell-search",
        attrId: "id",
        attrTxt: "gw-txt",
        attrUrl: "gw-url",
        attrShowHideParent: "gw-showhide-prnt",
        attrScrollTop:"gw-scroll-top"
    };
    gw.isIE = !!document.all || navigator.userAgent.indexOf(".NET") !== -1;
    gw.isIE8 = false;
    if (gw.isIE) {
        var version = parseFloat(navigator.appVersion.split("MSIE")[1]);
        gw.isIE8 = (version === 8 || version === 7);
    }
    gw.isMobile = (navigator.userAgent.indexOf("Mobile") !== -1 || navigator.userAgent.indexOf("Windows Phone") !== -1);
    gw.isTouch = gw.isMobile && (navigator.userAgent.indexOf("iPad") !== -1 || navigator.userAgent.indexOf("Android") !== -1);
    gw.isFirefox = (navigator.userAgent.indexOf("Firefox") !== -1);
    gw.isSafari = (navigator.userAgent.indexOf("Safari") !== -1);

    var charts = [];
    var tables = [];

    var locale = document.documentElement.lang;
    if (typeof (locale) === "undefined" || locale === "")
        locale = "en";


    var attrUrlLoadChildren = "gw-url-load-children",
            attrUrlSearch = "gw-url-load-search",
            attrUrlInit = "gw-url-load-init",
            attrId = "gw-id", attrOnClick = "gw-onclick", attrParentId = "gw-pr",
            attrExpanded = "gw-xp", attrSelected = "gw-sl", attrHasChild = "gw-ch",
            attrChildLoaded = "gw-ld",
            clsExpanded1 = "gw-tree-cell-expanded1",
            clsExpanded0 = "gw-tree-cell-expanded0",
            clsLoading = "gw-tree-cell-loading",
            clsTreeRow = "gw-table-row",
            clsTreeSearchResults = "gw-search-results",
            clsTreeSearchProgress = "gw-search-progress",
            clsTreeSearchIcon = "gw-search-button",
            clsTreeSearchClear = "gw-search-clear",
            pParentId = "[parent_id]",
            pSearchText = "[search_text]";
    var percentUps = [1, 2, 3, 4, 5, 6, 8, 8, 9, 10, 10, 12, 15, 15, 15, 15, 20, 20, 20, 20, 20, 24, 24, 25, 25, 25, 30, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100];
    var percentSteps = [0.2, 0.5, 1, 1, 1, 2, 2, 2, 3, 2, 2, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 6, 6, 5, 5, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20];
    var colors = ["#C32148", "#F0E130", "#0070FF", "#8806CE", "#BD33A4", "#FF7E00", "#96C8A2", "#6C541E", "#FFA700", "#5E93A1"];
    var formats = {
        en: {
            groupSize: 3,
            groupDelimiter: " ",
            decimalDelimiter: ".",
            bigNumbersPostfixes: {
                1: "",
                1000: " K",
                1000000: " M",
                1000000000: " B",
                1000000000000: " T"
            }
        },
        ru: {
            groupSize: 3,
            groupDelimiter: " ",
            decimalDelimiter: ",",
            bigNumbersPostfixes: {
                1: "",
                1000: " тыс.",
                1000000: " млн",
                1000000000: " млрд",
                1000000000000: " трлн"
            }
        }
    };
    var shortFormatsMap = {
        0: {denominator: 1, minDec: 0, maxDec: 0},
        1: {denominator: 1, minDec: 2, maxDec: 5},
        2: {denominator: 1, minDec: 2, maxDec: 2},
        3: {denominator: 1, minDec: 0, maxDec: 0},
        4: {denominator: 1000, minDec: 2, maxDec: 2},
        5: {denominator: 1000, minDec: 2, maxDec: 2},
        6: {denominator: 1000, minDec: 0, maxDec: 0},
        7: {denominator: 1000000, minDec: 2, maxDec: 2},
        8: {denominator: 1000000, minDec: 2, maxDec: 2},
        9: {denominator: 1000000, minDec: 0, maxDec: 0},
        10: {denominator: 1000000000, minDec: 2, maxDec: 2},
        11: {denominator: 1000000000, minDec: 2, maxDec: 2},
        12: {denominator: 1000000000, minDec: 0, maxDec: 0},
        13: {denominator: 1000000000000, minDec: 2, maxDec: 2},
        14: {denominator: 1000000000000, minDec: 2, maxDec: 2},
        15: {denominator: 1000000000000, minDec: 0, maxDec: 0},
        16: {denominator: 1000000000000, minDec: 0, maxDec: 0},
        17: {denominator: 1000000000000, minDec: 0, maxDec: 0}
    };
    var shortFormatsMapForHeaders = {
        0: {denominator: 1, minDec: 0, maxDec: 0},
        1: {denominator: 1, minDec: 1, maxDec: 1},
        2: {denominator: 1, minDec: 0, maxDec: 1},
        3: {denominator: 1, minDec: 0, maxDec: 1},
        4: {denominator: 1000, minDec: 1, maxDec: 1},
        5: {denominator: 1000, minDec: 0, maxDec: 1},
        6: {denominator: 1000, minDec: 0, maxDec: 0},
        7: {denominator: 1000000, minDec: 1, maxDec: 1},
        8: {denominator: 1000000, minDec: 0, maxDec: 1},
        9: {denominator: 1000000, minDec: 0, maxDec: 0},
        10: {denominator: 1000000000, minDec: 1, maxDec: 1},
        11: {denominator: 1000000000, minDec: 0, maxDec: 1},
        12: {denominator: 1000000000, minDec: 0, maxDec: 0},
        13: {denominator: 1000000000000, minDec: 1, maxDec: 1},
        14: {denominator: 1000000000000, minDec: 0, maxDec: 1},
        15: {denominator: 1000000000000, minDec: 0, maxDec: 0},
        16: {denominator: 1000000000000, minDec: 0, maxDec: 0},
        17: {denominator: 1000000000000, minDec: 0, maxDec: 0}
    };

    function getPercentStep(percent) {
        if (percent >= 0 & percent <= 100)
            return percentSteps[percent];
        else
            return percent;
    }
    function getPercent(value, digits) {
        return parseInt(Math.abs(value) / Math.pow(10, digits) * 100);
    }
    function getFormattedNumber(value, groupSize, groupDelimiter, minDecimalSize, maxDecimalSize, decimalDelimiter) {
        if (typeof (value) === "undefined" || value === null)
            return "";
        var sign = getSign(value).toString().replace("1", "");
        value = Math.abs(parseFloat(value));
        var digits = value.toString().split('');
        var decimalIndex = -1;
        if (digits.indexOf)
            decimalIndex = digits.indexOf(".");
        else
            for (var i = 0; i < digits.length; i++) {
                if (digits[i] === ".") {
                    decimalIndex = i;
                    break;
                }
            }

        var intLength = decimalIndex === -1 ? digits.length : decimalIndex;
        var gs = intLength - parseInt(intLength / groupSize) * groupSize;
        gs = gs === 0 ? groupSize : gs;
        var r = [];
        var g = 0;
        for (var i = 0; i < intLength; i++) {
            r.push(digits[i]);
            g++;
            if (g === gs && i !== intLength - 1) {
                r.push(groupDelimiter);
                g = 0;
                gs = groupSize;
            }
        }
        if (minDecimalSize > 0) {
            r.push(decimalDelimiter);
            if (decimalIndex === -1) {
                for (var i = 0; i < maxDecimalSize; i++) {
                    r.push("0");
                }
            } else {
                var dec0 = value.toString().substr(decimalIndex + 1, digits.length);
                var dec = parseInt(dec0);
                var decL = dec0.toString().length;
                for (var i = minDecimalSize; i <= maxDecimalSize; i++) {
                    var v = Math.round(dec / Math.pow(10, decL - i), 0);
                    if (v > 0) {
                        r.push(v.toString());
                        break;
                    } else if (v === maxDecimalSize) {
                        for (var j = 0; j < maxDecimalSize; j++) {
                            r.push("0");
                        }
                    }
                }
            }
        }
        return sign + r.join('');
    }
    function getLocalizedFormattedNumber(value, locale, minDecimalSize, maxDecimalSize) {
        var f = formats.en;
        switch (locale) {
            case "ru":
                f = formats.ru;
                break;
        }
        ;
        return getFormattedNumber(value, f.groupSize, f.groupDelimiter, minDecimalSize || 0, maxDecimalSize || 0, f.decimalDelimiter);
    }
    function getLocalizedShortFormattedNumber(value, locale, forHeaders) {
        var digits = parseInt(Math.abs(value)).toString().length;
        var sf = digits >= 0 & digits <= 17
                ? (forHeaders ? shortFormatsMapForHeaders : shortFormatsMap)[digits]
                : (forHeaders ? shortFormatsMapForHeaders : shortFormatsMap)[0];
        var v = getLocalizedFormattedNumber(value / sf.denominator, locale, sf.minDec, sf.maxDec);
        var f = formats.en;
        switch (locale) {
            case "ru":
                f = formats.ru;
                break;
        }
        ;
        return v + f.bigNumbersPostfixes[sf.denominator];
    }
    function getSign(value) {
        if (Math.sign)
            return Math.sign(value);
        else
            return value < 0 ? -1 : 1;
    }

    function getCharWidth(char) {
        switch (char) {
            case "i":
            case "l":
                return 3;
            case "f":
            case "j":
            case "t":
                return 4;
            case "I":
            case "J":
            case "r":
            case "г":
                return 5;
            case "L":
            case "c":
            case "k":
            case "s":
            case "v":
            case "x":
            case "y":
            case "z":
            case "з":
            case "к":
            case "с":
            case "т":
            case "у":
            case "х":
            case "э":
                return 6;
            case "E":
            case "F":
            case "P":
            case "S":
            case "Y":
            case "Z":
            case "Г":
            case "Е":
            case "Ё":
            case "З":
            case "Р":
            case "У":
            case "a":
            case "b":
            case "d":
            case "e":
            case "g":
            case "h":
            case "n":
            case "o":
            case "p":
            case "q":
            case "u":
            case "а":
            case "б":
            case "в":
            case "д":
            case "е":
            case "ё":
            case "и":
            case "й":
            case "л":
            case "н":
            case "о":
            case "п":
            case "р":
            case "ц":
            case "ч":
            case "ъ":
            case "ь":
            case "я":
                return 7;
            case "A":
            case "B":
            case "C":
            case "K":
            case "R":
            case "T":
            case "V":
            case "X":
            case "А":
            case "Б":
            case "В":
            case "К":
            case "С":
            case "Т":
            case "Х":
            case "Ч":
            case "Ь":
            case "Э":
            case "Я":
            case "м":
                return 8;
            case "D":
            case "G":
            case "H":
            case "N":
            case "O":
            case "Q":
            case "U":
            case "Д":
            case "И":
            case "Й":
            case "Л":
            case "Н":
            case "О":
            case "П":
            case "Ц":
            case "Ъ":
            case "ж":
            case "ы":
                return 9;
            case "M":
            case "М":
            case "Ф":
            case "Ы":
            case "w":
            case "ф":
            case "ш":
            case "щ":
            case "ю":
                return 10;
            case "m":
                return 11;
            case "W":
            case "Ж":
            case "Ш":
            case "Щ":
            case "Ю":
                return 12;
            default:
                return 8;
        }
    }
    function getTextHeight(text, width) {
        var words = text.split(" ");
        var lineLength = 0;
        var rowsCount = 0;
        for (var i = 0; i < words.length; i++) {
            var w = getTextWidth(words[i]);
            if (lineLength + w < width) {
                lineLength += w + 8; /* 8 = space*/
            } else {
                lineLength = w;
                rowsCount++;
            }
        }
        rowsCount++;
        return rowsCount;
    }
    function arrayContains(arr, obj) {
        if (!arr)
            return false;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] == obj)
                return true;
        }
        return false;
    }
    function arrayIndexOf(arr, obj) {
        if (!arr)
            return -1;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i] == obj)
                return i;
        }
        return -1;
    }

    function startShowBalloon(t, html, color, leftPlus, topPlus) {
        stopShowBalloon(t);
        leftPlus = leftPlus || 15;
        topPlus = topPlus || 0;
        var b = document.createElement("div");
        var offset = $(t).offset();
        $(b)
                .addClass("gw-balloon")
                .html(html)
                .zIndex(1001)
                .appendTo($(document.body))
                .css("border-color", color)
                .css("max-width", "200px")
                .offset({top: offset.top + topPlus, left: offset.left + leftPlus});
        if (!gw.isIE8) {
            $(t).mouseleave(function () {
                $(b).remove();
            });
        }
    }
    function stopShowBalloon(t) {
        $(".gw-balloon").remove();
    }
    gw.initChart = function (cnt) {
        if ($(cnt).children().length === 0)
            return null;
        var chart = {
            container: $(cnt),
            padding: {left: 2, right: 10, top: 4, bottom: 12},
            axisX: {
                values: [],
                labels: [],
                labelMargin: 10,
                defaultLabelWidth: 30,
                labelHeight: 15,
                minValue: 9999,
                maxValue: -9999,
                minValues: [],
                maxValues: [],
                sectors: [],
                text: {font: '12px Tahoma', fill: "#555", "text-anchor": "middle"},
                hoverText: {font: 'bold 12px Tahoma', fill: "white", "text-anchor": "middle"}
            },
            axisY: {
                text: {font: '12px Tahoma', fill: "#555", "text-anchor": "end"}
            },
            graphs: [],
            minValue: 0,
            maxValue: 1,
            count: 0,
            mainLineColor: "#111",
            hoverLineColor: "#CC0000",
            additionalLineColor: "#999",
            drag: {
                left: {
                    isDragging: false,
                    percent: 0,
                    value: null
                },
                right: {
                    isDragging: false,
                    percent: 1,
                    value: null
                },
                middle: {
                },
                backStart: {},
                backEnd: {}
            },
            onclick: function () {
            }
        };
        chart.refreshDragValuesLeft = function () {
            var previousValue = chart.drag.left.value;
            chart.axisX.minIndex = Math.max(0, Math.min(chart.count - 1, Math.round((chart.count - 1) * chart.drag.left.percent)));
            chart.drag.left.value = chart.axisX.values[chart.axisX.minIndex];
            chart.drag.left.elcaption.text(chart.axisX.labels[chart.axisX.minIndex]);
            return chart.drag.left.value !== previousValue;
        };
        chart.refreshDragValuesRight = function () {
            var previousValue = chart.drag.right.value;
            chart.axisX.maxIndex = Math.max(0, Math.min(chart.count - 1, Math.round((chart.count - 1) * chart.drag.right.percent)));
            chart.drag.right.value = chart.axisX.values[chart.axisX.maxIndex];
            chart.drag.right.elcaption.text(chart.axisX.labels[chart.axisX.maxIndex]);
            return chart.drag.right.value !== previousValue;
        };
        chart.refreshDragMiddle = function () {
            var l = chart.drag.left.el.css("left");
            var li = parseInt(l.replace("px", ""));
            var r = chart.drag.right.el.css("right");
            var ri = parseInt(r.replace("px", ""));
            var pW = chart.drag.left.el.parent().width();
            var lW = chart.drag.left.el.width();
            var rW = chart.drag.right.el.width();
            chart.drag.middle.el.css("left", (li + 1).toString() + "px");
            chart.drag.middle.el.width(pW - ri - li - lW - rW - 14);
        };
        chart.setDragPosition = function () {
            var wP = chart.drag.left.el.parent().width() - chart.drag.right.el.width();
            var w1 = wP * chart.drag.left.percent,
                    w2 = chart.drag.left.el.width(),
                    w3 = wP * chart.drag.right.percent - w1 - w2,
                    w4 = chart.drag.right.el.width(),
                    w5 = wP - w1 - w2 - w3;
            chart.drag.backStart.el.width(w1);
            chart.drag.middle.el.width(w3);
            chart.drag.backEnd.el.width(w5);
        };
        chart.getDragParentWidth = function () {
            return chart.drag.left.el.parent().width() - chart.drag.right.el.width();
        };
        chart.getDragParentLeft = function () {
            return chart.drag.left.el.parent().offset().left;
        };
        chart.getDragParentRight = function () {
            return chart.drag.left.el.parent().width() + chart.drag.left.el.parent().offset().left;
        };
        chart.getDragLeftWidth = function () {
            return chart.drag.left.el.width() + 6;
        };
        chart.getDragRightWidth = function () {
            return chart.drag.right.el.width() + 6;
        };

        var onclickpfp = chart.container.attr(attrOnClick);
        if (onclickpfp) {
            chart.onclick = getFunction(onclickpfp);
        }

        chart.height = chart.container.attr("gw-graph-height");
        chart.type = chart.container.attr("gw-graph-type");
        chart.drag.backStart.el = chart.container.find(".gw-gr-drag-back-start");
        chart.drag.backEnd.el = chart.container.find(".gw-gr-drag-back-end");
        chart.drag.left.el = chart.container.find(".gw-gr-drag-left");
        chart.drag.left.elcaption = chart.drag.left.el.find(".gw-gr-drag-inside");
        chart.drag.right.el = chart.container.find(".gw-gr-drag-right");
        chart.drag.right.elcaption = chart.drag.right.el.find(".gw-gr-drag-inside");
        chart.drag.middle.el = chart.container.find(".gw-gr-drag-middle");
        chart.drag.left.initialValue = chart.container.attr("gw-graph-min");

        chart.backgroundColor = chart.container.find(".gw-gr-body").css("background-color");
        chart.locale = chart.container.attr("lang");
        chart.id = chart.container.attr("id");
        var index = 0;
        chart.container.find("thead th").each(function () {
            var th = $(this);
            var id = th.attr(attrId);
            var name = th.text();
            switch (th.attr("gw-gr-type")) {
                case "x":
                    {
                        chart.axisX.id = id;
                        chart.axisX.name = name;
                        chart.axisX.index = index;
                        th.remove();
                    }
                    break;
                case "g":
                    {
                        var graph = {
                            id: id,
                            name: name,
                            index: index,
                            circleRadius: 3,
                            lineWidth: 2,
                            minValue: 0,
                            maxValue: 1,
                            values: [],
                            labels: [],
                            shares: [],
                            balloons: []
                        };
                        graph.color = th.attr("gw-gr-color") || colors[index];
                        var balloonContent = th.find(".gw-balloon-content");
                        if (balloonContent) {
                            graph.balloonTemplate = balloonContent.html();
                        }
                        chart.graphs.push(graph);
                        index++;
                        th.remove();
                    }
                    break;
            }
        });
        var r = 0;
        chart.container.find("tbody tr").each(function () {
            var i = 0;
            $(this).find("td").each(function () {
                var value = parseFloat($(this).attr("gw-grv"));
                var label = $(this).text();
                if (i === 0) {
                    if (!isNaN(value)) {
                        chart.axisX.minValue = Math.min(chart.axisX.minValue, value);
                        chart.axisX.maxValue = Math.max(chart.axisX.maxValue, value);
                    }
                    chart.axisX.values.push(value);
                    chart.axisX.labels.push(label);
                    chart.axisX.minValues.push(NaN);
                    chart.axisX.maxValues.push(NaN);
                } else {
                    if (!isNaN(value)) {
                        chart.graphs[i - 1].minValue = Math.min(chart.graphs[i - 1].minValue, value);
                        chart.graphs[i - 1].maxValue = Math.max(chart.graphs[i - 1].maxValue, value);
                    }
                    if (isNaN(chart.axisX.minValues[r]))
                        chart.axisX.minValues[r] = value;
                    else if (!isNaN(value))
                        chart.axisX.minValues[r] = Math.min(chart.axisX.minValues[r], value);
                    if (isNaN(chart.axisX.maxValues[r]))
                        chart.axisX.maxValues[r] = value;
                    else if (!isNaN(value))
                        chart.axisX.maxValues[r] = Math.max(chart.axisX.maxValues[r], value);
                    chart.graphs[i - 1].values.push(value);
                    chart.graphs[i - 1].labels.push(label);
                    var share = $(this).attr("gw-grs");
                    if (share)
                        chart.graphs[i - 1].shares.push(share);
                }
                i++;
            });
            //$(this).remove();
            r++;
        });
        chart.container.find("table").remove();
        chart.count = r;

        if (chart.drag.left.initialValue) {
            for (var i = 0; i < chart.count; i++) {
                if (chart.axisX.values[i] == chart.drag.left.initialValue) {
                    chart.drag.left.value = chart.axisX.values[i];
                    chart.axisX.minIndex = i;
                    chart.drag.left.percent = i / chart.count;
                    break;
                }
            }
        }
        if (chart.drag.left.value === null) {
            chart.drag.left.value = chart.axisX.minValue;
            chart.axisX.minIndex = 0;
            chart.drag.left.percent = 0;
        }
        if (chart.drag.right.value === null) {
            chart.drag.right.value = chart.axisX.maxValue;
            chart.axisX.maxIndex = chart.count - 1;
            chart.drag.right.percent = 1;
        }
        if (chart.count > 0) {
            chart.drag.left.elcaption.text(chart.axisX.labels[chart.axisX.minIndex]);
            chart.drag.right.elcaption.text(chart.axisX.labels[chart.axisX.maxIndex]);
        }
        chart.setDragPosition();

        chart.container.on("vmousemove", function (event) {
            if (chart.drag.left.isDragging) {
                var widthParent = chart.getDragParentWidth();
                var leftParent = chart.getDragParentLeft();
                var leftEvent = Math.min(Math.max(0, event.pageX - leftParent - chart.drag.left.x), widthParent);
                chart.drag.left.percent = leftEvent / widthParent;
                chart.setDragPosition();
                chart.refreshDragValuesLeft();
            } else if (chart.drag.right.isDragging) {
                var widthParent = chart.getDragParentWidth();
                var leftParent = chart.getDragParentLeft();
                var leftEvent = Math.min(Math.max(0, event.pageX - leftParent - chart.drag.right.x), widthParent);
                chart.drag.right.percent = leftEvent / widthParent;
                chart.setDragPosition();
                chart.refreshDragValuesRight();
            } else {

            }
        });
        chart.container.on("vmouseup", function (event) {
            if (chart.drag.left.isDragging) {
                chart.drag.left.isDragging = false;
                chart.refresh();
            }
            else if (chart.drag.right.isDragging) {
                chart.drag.right.isDragging = false;
                chart.refresh();
            }
        });
        chart.container.on("vmouseleave", function (event) {
            if (chart.drag.left.isDragging) {
                chart.drag.left.isDragging = false;
                chart.refresh();
            }
            else if (chart.drag.right.isDragging) {
                chart.drag.right.isDragging = false;
                chart.refresh();
            }
            if (gw.isIE8) {
                $(".gw-balloon").remove();
            }

        });
        chart.drag.left.el.on("vmousedown", function (event) {
            chart.drag.left.isDragging = true;
            chart.drag.left.x = event.offsetX;
            if (!chart.drag.left.x && event.currentTarget) {
                chart.drag.left.x = event.pageX - event.currentTarget.offsetLeft;
            }
        });
        chart.drag.right.el.on("vmousedown", function (event) {
            chart.drag.right.isDragging = true;
            chart.drag.right.x = event.offsetX;
            if (!chart.drag.right.x && event.currentTarget) {
                chart.drag.right.x = event.pageX - event.currentTarget.offsetLeft;
            }
        });
        /*chart.container.find("table").height(chart.container.height());*/
        chart.container.find(".gw-gr-body").attr("id", chart.id + "body");
        chart.refresh = function () {
            chart.view = {
                minValue: chart.axisX.minValues[chart.axisX.minIndex],
                maxValue: chart.axisX.maxValues[chart.axisX.minIndex],
                axisY: {
                    values: [],
                    labels: [],
                    labelWidth: 0
                },
                axisX: {
                    values: [],
                    labels: [],
                    xS: [],
                    count: chart.axisX.maxIndex - chart.axisX.minIndex + 1
                },
                x: {min: 0, max: 0},
                y: {min: 0, max: 0}
            };

            chart.container.find(".gw-gr-body").children().remove();
            chart.view.width = chart.container.width() - 4;
            chart.view.height = chart.height;
            chart.container.children().show();
            chart.paper = Raphael(chart.id + "body", chart.view.width, chart.view.height);
            if (!gw.isIE8)
                $(chart.paper.canvas).css("position", "");
            var pMain = [], pAdditional = [];


            for (var i = chart.axisX.minIndex; i <= chart.axisX.maxIndex; i++) {
                chart.view.minValue = Math.min(chart.axisX.minValues[i], chart.view.minValue);
                chart.view.maxValue = Math.max(chart.axisX.maxValues[i], chart.view.maxValue);
                chart.view.axisX.values.push(chart.axisX.values[i]);
                chart.view.axisX.labels.push(chart.axisX.labels[i]);
            }
            var digitsK = .1, digits = 1;
            while (digits === 1) {
                digitsK = digitsK * 10;
                digits = Math.max(
                        parseInt(Math.abs(chart.view.minValue * digitsK)).toString().length,
                        parseInt(Math.abs(chart.view.maxValue * digitsK)).toString().length);
            }

            var percent = Math.max(
                    getPercent(chart.view.maxValue, digits),
                    getPercent(chart.view.minValue, digits));
            var percentStep = getPercentStep(percent) * digitsK;
            var minValue = Math.min(0, chart.view.minValue);
            var maxValue = Math.max(0, chart.view.maxValue);
            var tmpA = [], tmpI = 0, tmpV = 0;
            while (tmpV > minValue) {
                tmpI++;
                tmpV = -tmpI * percentStep * Math.pow(10, digits) / 100 / digitsK;
                tmpA.push(tmpV);
            }
            for (var i = tmpA.length - 1; i >= 0; i--) {
                chart.view.axisY.values.push(tmpA[i]);
            }
            chart.view.axisY.values.push(0);
            tmpI = 0;
            while (tmpV < maxValue) {
                tmpI++;
                tmpV = tmpI * percentStep * Math.pow(10, digits) / 100 / digitsK;
                chart.view.axisY.values.push(tmpV);
            }

            for (var i = 0; i < chart.view.axisY.values.length; i++) {
                var label = "";
                if (chart.view.axisY.values[i] === 0)
                    label = "0";
                else
                    label = getLocalizedShortFormattedNumber(
                            chart.view.axisY.values[i], chart.locale, true);
                chart.view.axisY.labelWidth = Math.max(label.length,
                        chart.view.axisY.labelWidth);
                chart.view.axisY.labels.push(label);
            }

            chart.view.axisY.minValue = chart.view.axisY.values[0];
            chart.view.axisY.maxValue = chart.view.axisY.values[chart.view.axisY.values.length - 1];

            var plMain = chart.paper.path().attr({stroke: chart.mainLineColor});
            var plAdditional = chart.paper.path().attr({stroke: chart.additionalLineColor});
            var axisYLeft = Math.round(chart.view.axisY.labelWidth * 7) + 10;
            var y;
            chart.view.y.max = Math.round(chart.view.height - chart.padding.bottom - chart.axisX.labelHeight) + .5;
            chart.view.y.min = Math.round(chart.padding.top) + .5;
            chart.view.axisY.distance = (chart.view.y.max - chart.view.y.min) / (chart.view.axisY.labels.length - 1);
            chart.view.x.max = Math.round(chart.view.width - chart.padding.right) + .5;
            chart.view.x.min = Math.round(axisYLeft) + .5;
            chart.view.axisX.distance = (chart.view.x.max - chart.view.x.min) / (chart.view.axisX.count);
            for (var i = 0; i < chart.view.axisY.labels.length; i++) {
                y = Math.round(chart.view.y.max - i * chart.view.axisY.distance) - .5;
                var x = Math.round(chart.view.axisY.labelWidth * 7);
                chart.paper.text(x, y, chart.view.axisY.labels[i]).attr(chart.axisY.text).toBack();
                if (chart.view.axisY.values[i] === 0 || i === 0)
                    pMain = pMain.concat(["M", chart.view.x.min, y, "H", chart.view.x.max]);
                else
                    pAdditional = pAdditional.concat(["M", chart.view.x.min, y, "H", chart.view.x.max]);
            }
            var yText = Math.round(chart.view.height - chart.padding.bottom - chart.axisX.labelHeight * 0.5) + .5;

            var prevLeft = 9999;
            for (var i = chart.axisX.maxIndex; i >= chart.axisX.minIndex; i--) {
                x = chart.view.x.min + (i - chart.axisX.minIndex + .5) * chart.view.axisX.distance;
                chart.view.axisX.xS.push(x);
                if (prevLeft > x + chart.axisX.defaultLabelWidth * .5 + chart.axisX.labelMargin) {
                    prevLeft = x - chart.axisX.defaultLabelWidth * .5;
                    chart.paper.text(x, yText, chart.view.axisX.labels[i - chart.axisX.minIndex]).attr(chart.axisX.text).toBack();
                    x = Math.round(chart.view.x.min + (i - chart.axisX.minIndex + 1) * chart.view.axisX.distance) - .5;
                    pAdditional = pAdditional.concat(["M", x, chart.view.y.max, "V", chart.view.y.min]);
                }
            }
            pMain = pMain.concat(["M", chart.view.x.min, chart.view.y.max, "V", chart.view.y.min]);
            plMain.attr({path: pMain});
            plAdditional.attr({path: pAdditional});
            var tV = chart.view.axisY.maxValue - chart.view.axisY.minValue;
            var tH = chart.view.height - chart.axisX.labelHeight - chart.padding.top - chart.padding.bottom;

            if (chart.type === "line") {

                var plGraphs = [], pGraphs = [], pCircles = [], pCircleAttrs = [], sectors = [];

                for (var j = chart.view.axisX.xS.length - 1; j >= 0; j--) {
                    var sector = chart.paper.set();
                    if (!gw.isIE8) {
                        sector.push(chart.paper.path().attr({stroke: chart.hoverLineColor, path: ["M", Math.round(chart.view.axisX.xS[j]) + .5, chart.view.y.max, "V", chart.view.y.min], opacity: 0}));
                        sector.push(chart.paper.rect(chart.view.axisX.xS[j] - chart.view.axisX.distance * .5, chart.view.y.min, chart.view.axisX.distance, chart.view.y.max - chart.view.y.min).attr({stroke: "none", fill: "white", opacity: 0})/**/.toBack());
                        sector.push(chart.paper.rect(Math.round(chart.view.axisX.xS[j] - chart.axisX.defaultLabelWidth * .7) - .5, chart.view.y.max + 1, Math.round(chart.axisX.defaultLabelWidth * 1.4), chart.axisX.labelHeight + 2).attr({stroke: "none", fill: chart.hoverLineColor, opacity: 0}));
                        sector.push(chart.paper.text(Math.round(chart.view.axisX.xS[j]) + .5, yText, chart.view.axisX.labels[chart.view.axisX.xS.length - j - 1]).attr(chart.axisX.hoverText)).attr({opacity: 0});
                        sectors.push(sector);
                    }
                    for (var i = 0; i < chart.graphs.length; i++) {
                        var graph = chart.graphs[i];
                        if (j === chart.view.axisX.xS.length - 1) {
                            plGraphs.push(chart.paper.path().attr({stroke: graph.color, "stroke-width": graph.lineWidth}));
                            pGraphs.push([]);
                            pCircles.push([]);
                            pCircleAttrs.push({fill: graph.color, stroke: graph.color, "stroke-width": graph.circleRadius, cursor: "pointer"});
                        }
                        var value = graph.values[chart.view.axisX.xS.length - j + chart.axisX.minIndex - 1];
                        if (!isNaN(value)) {
                            y = Math.round((chart.view.axisY.maxValue - value) * tH / tV + chart.padding.top) + .5;
                            pGraphs[i] = pGraphs[i].concat([pGraphs[i].length === 0 ? "M" : "L", chart.view.axisX.xS[j], y]);
                            pCircles[i].push({x: chart.view.axisX.xS[j], y: y});
                        } else {
                            pCircles[i].push(null);
                        }
                    }
                }

                for (var i = 0; i < plGraphs.length; i++) {
                    if (pGraphs[i].length > 0)
                        plGraphs[i].attr({path: pGraphs[i]});
                    var graph = chart.graphs[i];
                    for (var j = 0; j < pCircles[i].length; j++) {
                        if (pCircles[i][j] !== null) {
                            var circle = chart.paper
                                    .circle(pCircles[i][j].x, pCircles[i][j].y, graph.circleRadius)
                                    .attr(pCircleAttrs[i]);

                            (function (circle, graph, valueIndex) {
                                circle.hover(
                                        function () {
                                            circle.toFront();
                                            if (graph.balloonTemplate) {
                                                var html = graph.balloonTemplate;
                                                if (html.indexOf("[x]") > -1)
                                                    html = html.replace("[x]", chart.view.axisX.labels[valueIndex]);
                                                if (html.indexOf("[valueSF]") > -1)
                                                    html = html.replace("[valueSF]", getLocalizedShortFormattedNumber(graph.values[valueIndex + chart.axisX.minIndex], chart.locale));
                                                startShowBalloon(circle[0], html, graph.color);
                                            }
                                        });

                            })(circle, graph, j);

                            if (!gw.isIE8)
                                sectors[j].push(circle);
                        }
                    }
                }

                if (!gw.isIE8)
                    for (var i = 0; i < sectors.length; i++) {
                        (function (sector) {
                            var f_in = function (s) {
                                for (var i = 0; i < s.length; i++) {
                                    if (s.items[i].type === "circle") {
                                        s.items[i].attr({"stroke-width": graph.circleRadius * 3});
                                    } else {
                                        s.items[i].attr({opacity: 1});
                                    }
                                }
                            };
                            var f_out = function (s) {
                                for (var i = 0; i < s.length; i++) {
                                    if (s.items[i].type === "circle") {
                                        s.items[i].attr({"stroke-width": graph.circleRadius});
                                    } else {
                                        s.items[i].attr({opacity: 0});
                                    }
                                }
                            };
                            if (gw.isIE) {
                                sector.hover(function () {
                                    if (chart.view.activeSector)
                                        f_out(chart.view.activeSector);
                                    chart.view.activeSector = sector;
                                    f_in(sector);
                                }, function () {
                                    f_out(sector);
                                });
                            } else {
                                sector.hover(function () {
                                    f_in(sector);
                                }, function () {
                                    f_out(sector);
                                });
                            }
                        })(sectors[i]);
                    }

            } else if (chart.type === "bar") {
                var barWidth = chart.view.axisX.distance / chart.graphs.length;
                var barMargin = 4;
                for (var j = chart.view.axisX.xS.length - 1; j >= 0; j--) {
                    var values = [];
                    for (var i = 0; i < chart.graphs.length; i++) {
                        var graph = chart.graphs[i];
                        var value = graph.values[chart.view.axisX.xS.length - j + chart.axisX.minIndex - 1];
                        if (!isNaN(value)) {
                            y = Math.round((chart.view.axisY.maxValue - value) * tH / tV + chart.padding.top) - .5;
                            values.push({y: y, graph: graph, value: value});
                        }
                    }
                    values.sort(function (a, b) {
                        return b.value - a.value;
                    });
                    barWidth = chart.view.axisX.distance / chart.graphs.length;
                    for (var i = 0; i < values.length; i++) {
                        var bar = chart.paper
                                .rect(
                                        Math.round(chart.view.axisX.xS[j] - chart.view.axisX.distance * .5 + i * barWidth + barMargin * .5) + .5,
                                        values[i].y,
                                        Math.round(barWidth - barMargin) - .5,
                                        Math.round(chart.view.y.max - values[i].y) - .5
                                        )
                                .attr({stroke: "none", fill: values[i].graph.color, cursor: "pointer"});

                        (function (bar, graph, valueIndex, y) {
                            bar.hover(
                                    function () {
                                        if (graph.balloonTemplate) {
                                            var html = graph.balloonTemplate;
                                            if (html.indexOf("[x]") > -1)
                                                html = html.replace("[x]", chart.view.axisX.labels[valueIndex]);
                                            if (html.indexOf("[valueSF]") > -1)
                                                html = html.replace("[valueSF]", getLocalizedShortFormattedNumber(graph.values[valueIndex + chart.axisX.minIndex], chart.locale));
                                            if (html.indexOf("[share]") > -1)
                                                html = html.replace("[share]", graph.shares[valueIndex + chart.axisX.minIndex]);
                                            startShowBalloon(bar[0], html, graph.color,
                                                    Math.round(barWidth - barMargin),
                                                    -(y - chart.view.y.min));
                                        }
                                    });
                            bar.click(function () {
                                chart.onclick(graph.id);
                            });
                        })(bar, values[i].graph, chart.view.axisX.xS.length - 1 - j, values[i].y);
                    }
                }
            }

            chart.refreshDragMiddle();
        };
        charts.push(chart);
        return charts[charts.length - 1];
    };
    gw.initTree = function (cnt) {
        var tree = {
            body: $(cnt).children(gw.clsTreeBody),
            searchHeader: $(cnt).children(gw.clsTreeSearchHeader),
            searchText: $(cnt).children(gw.clsTreeSearchHeader).children(gw.clsSearchText),
            searchResults: $(cnt).children("." + clsTreeSearchResults),
            searchProgress: $(cnt).children(gw.clsTreeSearchHeader).children("." + clsTreeSearchProgress),
            searchIcon: $(cnt).children(gw.clsTreeSearchHeader).children("." + clsTreeSearchIcon),
            searchClear: $(cnt).children(gw.clsTreeSearchHeader).children("." + clsTreeSearchClear),
            searchResultsLoading: false,
            urlLoadChildren: $(cnt).attr(attrUrlLoadChildren),
            urlSearch: $(cnt).attr(attrUrlSearch)
        };

        tree.searchClear.click(function () {
            tree.searchText[0].value = "";
            tree.onSearchTextChanged();
        });

        tree.onRowClick = function (row, container) {
            var hasChild = parseInt(row.attr(attrHasChild));

            switch (hasChild) {
                case 1: /* потомки есть*/
                    {
                        var childLoaded = parseInt(row.attr(attrChildLoaded));
                        switch (childLoaded) {
                            case 0:/* потомки не загружены - загрузить их*/
                                {
                                    tree.loadRowChildren(row, container);
                                }
                                break;
                            case 1:/* потомки загружены */
                                {
                                    var expanded = parseInt(row.attr(attrExpanded));
                                    switch (expanded) {
                                        case 0: /* потомки скрыты - показать их*/
                                            {
                                                row.find("." + clsExpanded0)
                                                        .removeClass(clsExpanded0)
                                                        .addClass(clsExpanded1);
                                                row.attr(attrExpanded, 1);
                                                /*tree.showRowChildren(row);*/
                                                tree.showRow(row, container);
                                            }
                                            break;
                                        case 1:/* потомки открыты - скрыть их*/
                                            {
                                                /*tree.hideRowChildren(row);*/
                                                tree.hideRow(row, container);
                                                row.find("." + clsExpanded1)
                                                        .removeClass(clsExpanded1)
                                                        .addClass(clsExpanded0);
                                                row.attr(attrExpanded, 0);
                                                row.show();
                                            }
                                            break;
                                    }
                                }
                                break;
                        }
                    }
                    break;
            }
        };

        tree.loadRowChildren = function (row, container) {
            var pr = row.attr(attrId);
            var url = tree.urlLoadChildren.replace(pParentId, pr);

            row.find("." + clsExpanded0)
                    .removeClass(clsExpanded0)
                    .addClass(clsLoading);

            $.ajax({
                dataType: "text",
                url: url,
                success: function (data) {
                    var html = data.toString();
                    html = html.substr(html.indexOf(">") + 1).substr(("<div>").length);

                    var div = document.createElement('div');
                    div.innerHTML = html;
                    var d = div.childNodes;
                    for (var i = d.length - 1; i >= 0; i--) {
                        tree.subscribeRowToClick(d[i], container);
                        row.after(d[i]);
                    }
                    $(div).remove();

                    row.attr(attrChildLoaded, 1);
                    row.attr(attrExpanded, 1);
                    row.find("." + clsLoading)
                            .removeClass(clsLoading)
                            .addClass(clsExpanded1);
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    row.find("." + clsLoading)
                            .removeClass(clsLoading)
                            .addClass(clsExpanded0);
                }
            });
        };

        tree.showRow = function (row, container) {
            var hasChild = parseInt(row.attr(attrHasChild));
            var expanded = parseInt(row.attr(attrExpanded));

            if (hasChild) {
                if (expanded) {
                    var ch = container.find("[" + attrParentId + "  =" + row.attr(attrId) + "]");
                    ch.each(function () {
                        tree.showRow($(this), container);
                    });
                    ch.show();
                }
            }
            row.show();
        };

        tree.hideRow = function (row, container) {
            var hasChild = parseInt(row.attr(attrHasChild));
            if (hasChild) {
                var expanded = parseInt(row.attr(attrExpanded));
                if (expanded) {
                    var ch = container.find("[" + attrParentId + "  =" + row.attr(attrId) + "]");
                    ch.each(function () {
                        tree.hideRow($(this), container);
                    });
                }
            }
            row.hide();
        };

        tree.onSearchTextChanged = function () {
            if (tree.searchResultsLoading)
                return;
            var v = tree.searchText[0].value;
            if (tree.searchTextValue === v)
                return;
            tree.searchTextValue = v;
            var ws1 = v.split(" ");
            var ws2 = [];
            for (var i = 0; i < ws1.length; i++) {
                if (ws1[i].length > 2)
                    ws2.push(ws1[i]);
            }
            if (ws2.length > 0) {
                tree.doSearch(ws2);
            } else {
                tree.noSearch();
            }
        };

        tree.doSearch = function (ws) {
            tree.searchResultsLoading = true;
            tree.searchIcon.hide();
            tree.searchClear.hide();
            tree.searchProgress.show();
            var t = ws.join(" ");
            if (gw.isIE)
                t = encodeURI(t);
            var url = tree.urlSearch.replace(pSearchText, t);
            $.ajax({
                dataType: "text",
                url: url,
                success: function (data) {
                    var html = data.toString();
                    html = html.substr(html.indexOf(">") + 1).substr(("<div>").length);

                    tree.searchResults.children().remove();
                    tree.searchResults[0].innerHTML = html;

                    var re = new RegExp(ws.join("|"), 'gi');
                    tree.searchResults.find("." + clsTreeRow).each(function () {
                        var hrf = this.href;
                        if (typeof (hrf) === "undefined" && this.children.length > 0) {
                            for (var i = 0; i < this.children.length; i++) {
                                var hrf = this.children[i].href;
                                this.children[i].innerHTML = this.children[i].innerHTML.replace(re, function (x) {
                                    return "<span class='gw-search-hl'>" + x + "</span>";
                                });
                            }
                        } else {
                            this.innerHTML = this.innerHTML.replace(re, function (x) {
                                return "<span class='gw-search-hl'>" + x + "</span>";
                            });
                        }
                        this.href = hrf;
                    });

                    tree.subscribeToClicks(tree.searchResults);
                    tree.body.hide();
                    tree.searchResults.show();
                    tree.searchClear.show();
                    tree.searchProgress.hide();
                    tree.searchResultsLoading = false;
                    tree.onSearchTextChanged();
                },
                error: function (jqXHR, textStatus, errorThrown) {

                    tree.searchResultsLoading = false;
                    tree.onSearchTextChanged();
                }
            });
        };

        tree.noSearch = function () {
            tree.searchResults.hide();
            tree.searchProgress.hide();
            tree.searchClear.hide();
            tree.searchIcon.show();
            tree.body.show();
        };

        tree.subscribeToClicks = function (container) {
            container.children("." + clsTreeRow).each(function () {
                tree.subscribeRowToClick(this, container);
            });
        };
        tree.subscribeRowToClick = function (row, container) {
            $(row).click(function (event) {
                if (row.tagName.toLowerCase() === "div") {
                    tree.onRowClick($(row), container, event);
                }
            });
        };

        tree.subscribeToClicks(tree.body);

        if (tree.searchText.length > 0) {
            var ti = tree.searchText[0];
            if (typeof (ti.onchange !== "undefined"))
                ti.onchange = tree.onSearchTextChanged;
            if (typeof (ti.onpaste !== "undefined"))
                ti.onpaste = tree.onSearchTextChanged;
            if (typeof (ti.onautocomplete !== "undefined"))
                ti.onautocomplete = tree.onSearchTextChanged;
            if (typeof (ti.oninput !== "undefined"))
                ti.oninput = tree.onSearchTextChanged;
            if (typeof (ti.onkeyup !== "undefined"))
                ti.onkeyup = tree.onSearchTextChanged;
            tree.searchTextValue = "";
        }
    };

    gw.loadInitTree = function (cnt) {
        var url = $(cnt).attr(attrUrlInit);
        var divWait = document.createElement('div');
        divWait.innerHTML = gw.htmlWait;
        var searchHeader = $(cnt).children(gw.clsTreeSearchHeader);
        searchHeader.after(divWait);
        $.ajax({
            dataType: "text",
            url: url,
            success: function (data) {
                var html = data.toString();
                var div = document.createElement('div');
                $(divWait).remove();
                div.innerHTML = html;
                var d = div.childNodes;
                for (var i = d.length - 1; i >= 0; i--) {
                    searchHeader.after(d[i]);
                }
                $(div).remove();
                gw.initTree(cnt);
            },
            error: function (jqXHR, textStatus, errorThrown) {
            }
        });
    };

    var pbw = 0, pbh = 0;
    gw.resize = function () {
        var bw = $(document.body).width(), bh = $(document.body).height();
        var cw = pbw !== bw, ch = pbh !== bh;
        pbw = bw, pbh = bh;
        if (!cw)
            return;
        $(".gw-gr").children(".gw-gr-body").children().remove();
        $(".gw-t-cnt").children("table").hide();

        for (var i = 0; i < charts.length; i++) {
            if (charts[i].isResizing)
                return;
            charts[i].isResizing = true;
            charts[i].setDragPosition();
            charts[i].refresh();
            charts[i].isResizing = false;
        }

        $(".gw-t-cnt").each(function () {
            $(this).css("width", "");
            var w = $(this).width() - 2;
            $(this).css("width", w.toString() + "px");
            $(this).children("table").show();
        });

    };

    function startShowHtmlBalloon(e) {
        if (!e)
            return;
        var t = e.toElement || e.currentTarget || e.srcElement;
        $(t).find(".gw-balloon").remove();
        var b = document.createElement("div");
        var cnt = $(t).find(".gw-balloon-content");
        if (cnt.hasClass("gw-blid"))
            cnt = $("#" + cnt.attr("gw-blid"));
        var bcol = cnt.length > 0 ? cnt[0].style["border-color"] : cnt.css("border-color");
        $(b)
                .addClass("gw-balloon")
                .html(cnt.html())
                .zIndex(1001)
                .appendTo($(document.body))
                .position({my: "left+5 top+5", of: e, collision: "fit"})
                .css("border-color", bcol)
                ;
        var mm = function (em) {
            $(b).position({my: "left+5 top+5", of: em, collision: "fit"});
        };
        var ml = function (el) {
            var tl = el.toElement || el.currentTarget || el.srcElement;
            if ($.contains(b, tl))
                mm(el);
            else
                $(b).remove();
        };
        $(t).mousemove(function (em) {
            mm(em);
        });
        $(b).mousemove(function (em) {
            mm(em);
        });
        $(t).mouseleave(function (el) {
            ml(el);
        });
        $(b).mouseleave(function (el) {
            ml(el);
        });
    }

    gw.subscribeToBalloons = function (cnt) {
        if (cnt) {
            $(cnt).find(".gw-balloon-content").parent().mouseenter(function (event) {
                startShowHtmlBalloon(event);
            });
        } else {
            $(".gw-balloon-content").parent().mouseenter(function (event) {
                startShowHtmlBalloon(event);
            });
        }
    };

    var clsPopup = "gw-pp";
    function startShowHtmlPopup(pp, e) {
        if (!e)
            return;
        var t = e.toElement || e.currentTarget || e.srcElement;
        $("." + clsPopup).each(function () {
            if (this != pp[0]) {
                $(this).hide();
                var id = $(this).attr(attrId);
                if (id)
                    sessionStorage[clsPopup + "_" + id + "_open"] = 0;
            }
        });
        pp.show();
        pp
                .zIndex(1001)
                .position({my: "left+20 top", of: t, collision: "fit"});

        var id = pp.attr(attrId);
        if (id)
            sessionStorage[clsPopup + "_" + id + "_open"] = 1;

        var ml = function () {
            pp.off("vmouseleave.popup");
            $(document.body).on("click.popup", lf);
            pp.on("vmouseover.popup", me);
        };

        var me = function () {
            pp.off("vmouseover.popup");
            $(document.body).off("click.popup");
            pp.on("vmouseleave.popup", ml);
        };

        var lf = function (event) {
            if (gw.isTouch && event.target === t) {
                return;
            }
            $(document.body).off("click.popup");
            pp.off("vmouseover.popup");
            pp.off("vmouseleave.popup");
            pp.fadeOut(150);
            if (id) {
                sessionStorage[clsPopup + "_" + id + "_open"] = 0;
            }
        };

        ml();
    }
    gw.subscribeToPopups = function () {
        $("." + clsPopup).parent().each(function () {
            var pp = $(this).children("." + clsPopup);
            if (pp.length === 0)
                return;
            document.body.appendChild(pp[0]);
//            if (gw.isTouch) {
//                $(this).on("tap", function (event) {
//                    startShowHtmlPopup(pp, event);
//                });
//            } else {
//                $(this).mouseenter(function (event) {
//                startShowHtmlPopup(pp, event);
//            });
//            }   

            $(this).on("vmouseover", function (event) {
                startShowHtmlPopup(pp, event);
            });

//            var id = pp.attr(attrId);
//            if (id) {
//                var sessV = sessionStorage[clsPopup + "_" + id + "_open"];
//                if (typeof (sessV) !== "undefined" && parseInt(sessV) === 1) {
//                    startShowHtmlPopup(pp, {toElement: this});
//                }
//            }
        });
    };

    var attrUrlLoadTable = "gw-url-load-table";
    gw.initTable = function (cnt) {
        var url = $(cnt).attr(attrUrlLoadTable);
        if (url) {
            $.ajax({
                dataType: "text",
                url: url,
                success: function (data) {
                    var html = data.toString();
                    var div = document.createElement('div');
                    div.innerHTML = html;
                    var d = div.childNodes;
                    $(cnt).children().fadeOut(300, function () {
                        $(cnt).children().remove();
                        for (var i = d.length - 1; i >= 0; i--) {
                            $(cnt).append(d[i]);
                        }
                        gw.subscribeToBalloons(cnt);
                        $(div).remove();
                        $(cnt).attr(attrUrlLoadTable, "");
                    });
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    //alert(textStatus);
                }
            });
        }

    };

    var clsSelect = "gw-slct",
            clsSelectContent = "gw-slct-cnt",
            clsSelectOption = "gw-slct-opt",
            clsSelectValue = "gw-slct-vl",
            attrOnChange = "gw-onchange",
            attrParam = "gw-prm";
    gw.initSelects = function () {
        $("." + clsSelect).each(function () {
            initSelect($(this));
        });
    };
    function initSelect(cnt) {
        cnt.click(function () {
            selectOpenOrClose(cnt);
        });
        cnt.mouseleave(function () {
            selectClose(cnt);
        });
        cnt.find("." + clsSelectOption).click(function (e) {
            var t = $(e.toElement || e.currentTarget || e.srcElement);

            if (!(t.hasClass(clsSelectOption)))
                t = t.parent();
            if (!(t.hasClass(clsSelectOption)))
                t = t.parent();

            cnt.attr(attrId, t.attr(attrId));
            cnt.find("." + clsSelectValue).html(t.html());
            cnt.find("." + clsSelectValue).height(cnt.height());
            var f = getFunction(cnt.attr(attrOnChange));
            if (f !== null)
                f();
        });
        cnt.zIndex(1400);
        var options = cnt.find("." + clsSelectOption);
        var cntId = cnt.attr(attrId);
        if (!cntId) {
            if (options.length > 0) {
                cnt.find("." + clsSelectValue).html($(options[0]).html());
                cnt.find("." + clsSelectValue).height(cnt.height());
                cnt.attr(attrId, $(options[0]).attr(attrId));
                var f = getFunction(cnt.attr(attrOnChange));
                if (f !== null)
                    f();
            }
        }
//        else {
//            cnt.find("." + clsSelectValue).html(options.find("[" + attrId + "=" + cntId + "]").html());
//            cnt.find("." + clsSelectValue).height(cnt.height());
//            cnt.find("." + clsSelectValue).find("a").attr("href", "");
//        }
    }
    function selectOpenOrClose(cnt) {
        var open = cnt.attr("gw-open");
        open = (typeof (open) !== "undefined" && parseInt(open) === 1) ? true : false;
        if (open) {
            selectClose(cnt);
        } else {
            selectOpen(cnt);
        }
    }
    function selectOpen(cnt) {
        cnt.find("." + clsSelectContent).fadeIn(100);
        cnt.attr("gw-open", 1);

    }
    function selectClose(cnt) {
        cnt.find("." + clsSelectContent).fadeOut(100);
        cnt.attr("gw-open", 0);
    }

    function getFunction(fp) {
        if (typeof (fp) === "undefined")
            return null;
        fp = fp.split(".");
        var r = "";
        if (fp.length > 0) {
            r = window[fp[0]];
        }
        for (var i = 1; i < fp.length; i++) {
            r = r[fp[i]];
        }
        if (r === "")
            return null;
        else
            return r;
    }

    gw.getFormattedNumber = function (value, minDecimalSize, maxDecimalSize) {
        return getLocalizedFormattedNumber(value, locale, minDecimalSize, maxDecimalSize);
    };

    var clsSunburst = ".gw-sunburst";
    gw.initD3Charts = function () {
        if (typeof (gwSunburst) !== undefined) {
            $(clsSunburst).each(function () {
                var gid = $(this).attr("id");
            });
        }
    };

    gw.getSelectValue = function (code) {
        return $("." + clsSelect + "[" + attrParam + "='" + code + "']").attr(attrId);
    };

    gw.doMainSearch = function () {
        var filterText = gw.mainSearch.children(gw.clsSearchText)[0].value;
        var url = gw.mainSearch.attr(gw.attrUrl).replace("[filterText]", filterText);
        document.location.pathname = url;
    };

    gw.initMainSearch = function (ms) {
        gw.mainSearch = $(ms);
        gw.mainSearch.keyup(function (e) {
            if (e.keyCode === 13) {
                gw.doMainSearch();
            }
        });
        gw.mainSearch.parent().parent().find(gw.clsCellSearch).click(function () {
            gw.doMainSearch();
        });
        gw.mainSearch.children(gw.clsSearchMainButton).click(function () {
            gw.doMainSearch();
        });
    };

    gw.loadChart = function (cnt, url) {
        cnt = $(cnt);
        cnt.html(gw.htmlWait);
        $.ajax({
            dataType: "text",
            url: url,
            success: function (data) {
                var html = data.toString();
                var div = document.createElement('div');
                div.innerHTML = html;
                html = div.firstChild.innerHTML;
                $(div).remove();
                cnt.children().fadeOut(100, function () {
                    cnt.children().remove();
                    cnt.html(html);
                    var chart = gw.initChart(cnt);
                    if (chart != null)
                        chart.refresh();
                });
            },
            error: function (jqXHR, textStatus, errorThrown) {
                row.find("." + clsLoading)
                        .removeClass(clsLoading)
                        .addClass(clsExpanded0);
            }
        });

    };
    gw.getUrlInclude = function (url1, url2, url3, urlCode) {
        var codes = url2.split("-");
        for (var i = 0; i < codes.length; i++) {
            if (codes[i] === urlCode)
                return url1 + url2 + url3;
        }
        codes.push(urlCode);
        return url = url1 + codes.join("-") + url3;
    };

    gw.highlightText = function (cnt) {
        var txt = $(cnt).attr(gw.attrTxt);
        var ws = gw.getSearchTextArray(txt);
        var re = new RegExp(ws.join("|"), 'gi');
        cnt.innerHTML = cnt.innerHTML.replace(re, function (x) {
            return "<span class='" + gw.clsSearchHilghlight + "'>" + x + "</span>";
        });
    };

    gw.getSearchTextArray = function (v) {
        var ws1 = v.split(" ");
        var ws2 = [];
        for (var i = 0; i < ws1.length; i++) {
            if (ws1[i].length > 2)
                ws2.push(ws1[i]);
        }
        return ws2;
    };

    gw.initShowHide = function (p) {
        p.click(function () {
            if (p.hasClass(gw.clsPressedBack)) {
                p.removeClass(gw.clsPressedBack);
                $(gw.clsShowHideChild + "[" + gw.attrShowHideParent + "='" + $(this).attr(gw.attrId) + "']").fadeOut(100);
            } else {
                $("." + gw.clsPressedBack).removeClass(gw.clsPressedBack);
                $(gw.clsShowHideChild).hide();
                if (typeof(p.attr(gw.attrScrollTop)) !== "undefined"){
                    $(document).scrollTop(parseInt(p.attr(gw.attrScrollTop)));
                }                
                p.addClass(gw.clsPressedBack);
                $(gw.clsShowHideChild + "[" + gw.attrShowHideParent + "='" + $(this).attr(gw.attrId) + "']").fadeIn(100);
            }
        });
    };

    this.gw = gw;
    this.gw.menu = {
        zIndexStart: 1200,
        zIndexMax: 1200,
        menuMouseLeave: function (event) {
            var target = event.toElement || event.explicitOriginalTarget || event.relatedTarget;
            var p = $(target);
            while (p.length === 1) {
                p = p.parent();
                if (p.hasClass("gw-menu-block")) {
                    return;
                }
            }
            gw.menu.hideMenus();
        },
        activateMenu: function (btn) {
            if (btn === null
                    || (btn.nextElementSibling || btn.nextSibling) === null
                    || $(btn).hasClass("gw-menu-main-item-hover")) {
                return;
            }
            btn = $(btn);
            // jsRgtId
            var btnExpand = btn.find(".gw-table-cell-expanded");
            // jsBtmId
            var btnBtm = btn.next();
            if (btnBtm.length === 0)
                return;
            // jsCntId
            var btnCnt = btnBtm.next();
            btnExpand.addClass("gw-table-cell-border-hover");
            gw.menu.hideMenus();

            btn.addClass("gw-menu-main-item-hover");
            btnBtm.addClass("gw-menu-main-item-bottom-hover");
            btnCnt.addClass("gw-menu-main-item-content-hover");
            btnBtm.position({at: "left bottom-4", my: "left top", of: btn});
            btnBtm.width(btn.outerWidth());
            btnCnt.position({at: "left bottom+2", my: "left top", of: btn});
            btnCnt.width(btnCnt.outerWidth());
            if (btnCnt.zIndex() < gw.menu.zIndexStart) {
                btnCnt.zIndex(gw.menu.zIndexMax++);
                btnBtm.zIndex(gw.menu.zIndexMax++);
            }
            $("." + clsPopup).hide();

            btnCnt.mouseleave(function (event) {
                gw.menu.menuMouseLeave(event);
            });
            btnBtm.mouseleave(function (event) {
                gw.menu.menuMouseLeave(event);
            });
            btn.mouseleave(function (event) {
                gw.menu.menuMouseLeave(event);
            });
        },
        hideMenus: function () {
            $(".gw-menu-main-item-content-hover").removeClass("gw-menu-main-item-content-hover");
            $(".gw-menu-main-item-bottom-hover").removeClass("gw-menu-main-item-bottom-hover");
            $(".gw-menu-main-item-hover").removeClass("gw-menu-main-item-hover");
            $(".gw-table-cell-border-hover").removeClass("gw-table-cell-border-hover");
        },
        onMouseOver: function (e) {
            var t = e.currentTarget || e.srcElement || e.target;
            if (t === null)
                return;
            var c = "gw-menu-main-item";
            if ($(t).hasClass(c)) {
                gw.menu.activateMenu(t);
            } else if ($(t).find("." + c).length > 0) {
                t = $(t).find("." + c)[0];
                gw.menu.activateMenu(t);
            }
            else if (t.parentElement !== null && $(t.parentElement).hasClass(c)) {
                t = t.parentElement;
                gw.menu.activateMenu(t);
            }
            else if (t.parentElement !== null && t.parentElement.parentElement !== null && $(t.parentElement.parentElement).hasClass(c)) {
                t = t.parentElement.parentElement;
                gw.menu.activateMenu(t);
            }
            else if (t.parentElement !== null && t.parentElement.parentElement !== null && t.parentElement.parentElement.parentElement !== null && $(t.parentElement.parentElement.parentElement).hasClass(c)) {
                t = t.parentElement.parentElement.parentElement;
                gw.menu.activateMenu(t);
            }
        }
    };
}();

window.onload = function () {
    $(".gw-gr").each(function () {
        gw.initChart(this);
    });
    $(".gw-tree").each(function () {
        if ($(this).children(gw.clsTreeBody).length === 0) {
            gw.loadInitTree(this);
        } else {
            gw.initTree(this);
        }
    });
    $(".gw-menu-main-item").each(function () {
        $(this).mouseover(function (e) {
            gw.menu.onMouseOver(e);
        });
    });
    $(".gw-td-fr").each(function () {
        $(this).height($(this).parent().height() - 2);
    });
    $(".gw-t-cnt").each(function () {
        gw.initTable(this);
    });
    $(gw.clsSearchMain).each(function () {
        gw.initMainSearch(this);
    });
    $(gw.clsSearchHilghlightTarget).each(function () {
        gw.highlightText(this);
    });
    $(gw.clsShowHide).each(function () {
        gw.initShowHide($(this));
    });
    gw.resize();
    gw.subscribeToBalloons();
    gw.subscribeToPopups();
    gw.initSelects();
    gw.initD3Charts();

    if (document.URL.indexOf("#") > -1) {
        if (gw.isFirefox) {
            $(document).scrollTop($(document).scrollTop() - 55);
        } else {
            var bookmark = document.URL.substr(document.URL.indexOf("#"));
            var offset = $(bookmark).offset();
            $(document).on("scroll", function () {
                $(document).scrollTop(offset.top - 55);
                $(document).off("scroll");
            });
        }

    }
};

window.onresize = function () {
    gw.resize();
};